# -*- coding: utf-8 -*-
"""
日期计算核心引擎
提供各种日期计算功能
"""

import pendulum
from datetime import datetime, timedelta, date
from typing import Dict, List, Optional, Tuple, Union
from .holiday_data import HolidayManager
from .lunar_calendar import LunarCalendar


class DateCalculator:
    """日期计算器核心类"""
    
    def __init__(self):
        """初始化日期计算器"""
        self.timezone = 'Asia/Shanghai'
        # 初始化节假日管理器
        self.holiday_manager = HolidayManager()
        # 初始化农历转换器
        self.lunar_calendar = LunarCalendar()
    
    def _is_holiday_safe(self, date_obj) -> bool:
        """安全的节假日检查"""
        return self.holiday_manager.is_holiday(date_obj)
    
    def _is_workday_safe(self, date_obj) -> bool:
        """安全的工作日检查"""
        return self.holiday_manager.is_workday(date_obj)
    
    def add_days(self, base_date: Union[str, datetime, pendulum.DateTime], days: int) -> Dict:
        """
        日期加减天数
        
        Args:
            base_date: 基础日期
            days: 要加减的天数（负数表示减）
            
        Returns:
            包含计算结果的字典
        """
        try:
            # 转换为pendulum对象
            if isinstance(base_date, str):
                base_dt = pendulum.parse(base_date, tz=self.timezone)
            elif isinstance(base_date, datetime):
                base_dt = pendulum.instance(base_date, tz=self.timezone)
            elif isinstance(base_date, date):
                base_dt = pendulum.datetime(base_date.year, base_date.month, base_date.day, tz=self.timezone)
            elif hasattr(base_date, 'year') and hasattr(base_date, 'month') and hasattr(base_date, 'day'):
                # 处理date对象
                base_dt = pendulum.datetime(base_date.year, base_date.month, base_date.day, tz=self.timezone)
            else:
                base_dt = base_date
            
            # 计算结果日期
            result_dt = base_dt.add(days=days)
            
            # 获取农历信息
            lunar_info = self._get_lunar_info(result_dt)
            
            # 构建返回结果
            result = {
                'base_date': base_dt,
                'result_date': result_dt,
                'days_added': days,
                'weekday': self._get_weekday_name(result_dt.weekday()),
                'is_weekend': result_dt.weekday() in [5, 6],
                'is_holiday': self._is_holiday_safe(result_dt),
                'formatted_date': result_dt.format('YYYY年MM月DD日'),
                'iso_date': result_dt.to_date_string(),
                'days_from_today': (result_dt.date() - pendulum.now(self.timezone).date()).days,
                'lunar_info': lunar_info
            }
            
            return result
            
        except Exception as e:
            raise ValueError(f"日期计算错误: {e}")
    
    def add_months(self, base_date: Union[str, datetime, pendulum.DateTime], months: int) -> Dict:
        """
        日期加减月数
        
        Args:
            base_date: 基础日期
            months: 要加减的月数
            
        Returns:
            包含计算结果的字典
        """
        try:
            if isinstance(base_date, str):
                base_dt = pendulum.parse(base_date, tz=self.timezone)
            elif isinstance(base_date, datetime):
                base_dt = pendulum.instance(base_date, tz=self.timezone)
            elif isinstance(base_date, date):
                base_dt = pendulum.datetime(base_date.year, base_date.month, base_date.day, tz=self.timezone)
            elif hasattr(base_date, 'year') and hasattr(base_date, 'month') and hasattr(base_date, 'day'):
                base_dt = pendulum.datetime(base_date.year, base_date.month, base_date.day, tz=self.timezone)
            else:
                base_dt = base_date
            
            result_dt = base_dt.add(months=months)
            
            # 获取农历信息
            lunar_info = self._get_lunar_info(result_dt)
            
            result = {
                'base_date': base_dt,
                'result_date': result_dt,
                'months_added': months,
                'weekday': self._get_weekday_name(result_dt.weekday()),
                'is_weekend': result_dt.weekday() in [5, 6],
                'is_holiday': self._is_holiday_safe(result_dt),
                'formatted_date': result_dt.format('YYYY年MM月DD日'),
                'iso_date': result_dt.to_date_string(),
                'days_from_today': (result_dt.date() - pendulum.now(self.timezone).date()).days,
                'lunar_info': lunar_info
            }
            
            return result
            
        except Exception as e:
            raise ValueError(f"月份计算错误: {e}")
    
    def calculate_interval(self, start_date: Union[str, datetime, pendulum.DateTime], 
                         end_date: Union[str, datetime, pendulum.DateTime]) -> Dict:
        """
        计算两个日期之间的间隔
        
        Args:
            start_date: 开始日期
            end_date: 结束日期
            
        Returns:
            包含间隔信息的字典
        """
        try:
            # 转换日期
            if isinstance(start_date, str):
                start_dt = pendulum.parse(start_date, tz=self.timezone)
            elif isinstance(start_date, datetime):
                start_dt = pendulum.instance(start_date, tz=self.timezone)
            elif isinstance(start_date, date):
                start_dt = pendulum.datetime(start_date.year, start_date.month, start_date.day, tz=self.timezone)
            elif hasattr(start_date, 'year') and hasattr(start_date, 'month') and hasattr(start_date, 'day'):
                start_dt = pendulum.datetime(start_date.year, start_date.month, start_date.day, tz=self.timezone)
            else:
                start_dt = start_date
                
            if isinstance(end_date, str):
                end_dt = pendulum.parse(end_date, tz=self.timezone)
            elif isinstance(end_date, datetime):
                end_dt = pendulum.instance(end_date, tz=self.timezone)
            elif isinstance(end_date, date):
                end_dt = pendulum.datetime(end_date.year, end_date.month, end_date.day, tz=self.timezone)
            elif hasattr(end_date, 'year') and hasattr(end_date, 'month') and hasattr(end_date, 'day'):
                end_dt = pendulum.datetime(end_date.year, end_date.month, end_date.day, tz=self.timezone)
            else:
                end_dt = end_date
            
            # 确保开始日期在结束日期之前
            if start_dt > end_dt:
                start_dt, end_dt = end_dt, start_dt
            
            # 计算间隔
            diff = end_dt - start_dt
            
            # 计算工作日数量
            workdays = self._calculate_workdays(start_dt, end_dt)
            
            result = {
                'start_date': start_dt,
                'end_date': end_dt,
                'total_days': diff.days,
                'total_hours': diff.total_seconds() / 3600,
                'total_minutes': diff.total_seconds() / 60,
                'workdays': workdays,
                'weekends': diff.days - workdays,
                'years': diff.days // 365,
                'months': diff.days // 30,
                'weeks': diff.days // 7,
                'formatted_interval': self._format_interval(diff.days)
            }
            
            return result
            
        except Exception as e:
            raise ValueError(f"间隔计算错误: {e}")
    
    def add_business_days(self, base_date: Union[str, datetime, pendulum.DateTime], 
                         business_days: int) -> Dict:
        """
        加减工作日（排除周末和节假日）
        
        Args:
            base_date: 基础日期
            business_days: 工作日数量
            
        Returns:
            包含计算结果的字典
        """
        try:
            if isinstance(base_date, str):
                base_dt = pendulum.parse(base_date, tz=self.timezone)
            elif isinstance(base_date, datetime):
                base_dt = pendulum.instance(base_date, tz=self.timezone)
            elif isinstance(base_date, date):
                base_dt = pendulum.datetime(base_date.year, base_date.month, base_date.day, tz=self.timezone)
            elif hasattr(base_date, 'year') and hasattr(base_date, 'month') and hasattr(base_date, 'day'):
                base_dt = pendulum.datetime(base_date.year, base_date.month, base_date.day, tz=self.timezone)
            else:
                base_dt = base_date
            
            current_dt = base_dt
            days_to_add = business_days
            direction = 1 if business_days > 0 else -1
            days_to_add = abs(days_to_add)
            
            while days_to_add > 0:
                current_dt = current_dt.add(days=direction)
                
                # 检查是否为工作日（非周末且非节假日）
                if self._is_workday_safe(current_dt):
                    days_to_add -= 1
            
            # 获取农历信息
            lunar_info = self._get_lunar_info(current_dt)
            
            result = {
                'base_date': base_dt,
                'result_date': current_dt,
                'business_days_added': business_days,
                'weekday': self._get_weekday_name(current_dt.weekday()),
                'is_weekend': current_dt.weekday() in [5, 6],
                'is_holiday': self._is_holiday_safe(current_dt),
                'formatted_date': current_dt.format('YYYY年MM月DD日'),
                'iso_date': current_dt.to_date_string(),
                'days_from_today': (current_dt.date() - pendulum.now(self.timezone).date()).days,
                'lunar_info': lunar_info
            }
            
            return result
            
        except Exception as e:
            raise ValueError(f"工作日计算错误: {e}")
    
    def get_date_info(self, date: Union[str, datetime, pendulum.DateTime]) -> Dict:
        """
        获取日期的详细信息
        
        Args:
            date: 要查询的日期
            
        Returns:
            包含日期信息的字典
        """
        try:
            if isinstance(date, str):
                dt = pendulum.parse(date, tz=self.timezone)
            elif isinstance(date, datetime):
                dt = pendulum.instance(date, tz=self.timezone)
            elif isinstance(date, date):
                dt = pendulum.datetime(date.year, date.month, date.day, tz=self.timezone)
            elif hasattr(date, 'year') and hasattr(date, 'month') and hasattr(date, 'day'):
                dt = pendulum.datetime(date.year, date.month, date.day, tz=self.timezone)
            else:
                dt = date
            
            # 获取农历信息（简化版）
            lunar_info = self._get_lunar_info(dt)
            
            result = {
                'date': dt,
                'formatted_date': dt.format('YYYY年MM月DD日'),
                'iso_date': dt.to_date_string(),
                'weekday': self._get_weekday_name(dt.weekday()),
                'weekday_num': dt.weekday() + 1,
                'is_weekend': dt.weekday() in [5, 6],
                'is_holiday': chinese_calendar.is_holiday(dt.date()),
                'holiday_name': self._get_holiday_name(dt.date()),
                'year': dt.year,
                'month': dt.month,
                'day': dt.day,
                'quarter': (dt.month - 1) // 3 + 1,
                'week_of_year': dt.week_of_year,
                'day_of_year': dt.day_of_year,
                'days_in_month': dt.days_in_month,
                'is_leap_year': dt.is_leap_year(),
                'lunar_info': lunar_info,
                'days_from_today': (dt.date() - pendulum.now(self.timezone).date()).days
            }
            
            return result
            
        except Exception as e:
            raise ValueError(f"日期信息获取错误: {e}")
    
    def _get_weekday_name(self, weekday: int) -> str:
        """获取星期名称"""
        weekdays = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日']
        return weekdays[weekday]
    
    def _calculate_workdays(self, start_dt: pendulum.DateTime, 
                          end_dt: pendulum.DateTime) -> int:
        """计算两个日期之间的工作日数量"""
        workdays = 0
        current_dt = start_dt
        
        while current_dt < end_dt:
            if self._is_workday_safe(current_dt):
                workdays += 1
            current_dt = current_dt.add(days=1)
        
        return workdays
    
    def _format_interval(self, days: int) -> str:
        """格式化间隔显示"""
        if days == 0:
            return "同一天"
        elif days == 1:
            return "1天"
        elif days < 7:
            return f"{days}天"
        elif days < 30:
            weeks = days // 7
            remaining_days = days % 7
            if remaining_days == 0:
                return f"{weeks}周"
            else:
                return f"{weeks}周{remaining_days}天"
        elif days < 365:
            months = days // 30
            remaining_days = days % 30
            if remaining_days == 0:
                return f"{months}个月"
            else:
                return f"{months}个月{remaining_days}天"
        else:
            years = days // 365
            remaining_days = days % 365
            if remaining_days == 0:
                return f"{years}年"
            else:
                return f"{years}年{remaining_days}天"
    
    def _get_holiday_name(self, date) -> Optional[str]:
        """获取节假日名称"""
        try:
            holiday_name = self.holiday_manager.get_holiday_name(date)
            return holiday_name if holiday_name else None
        except:
            return None
    
    def _get_lunar_info(self, dt: pendulum.DateTime) -> Dict:
        """获取农历信息"""
        return self.lunar_calendar.get_lunar_info(dt)
